package com.unis.service.system.impl;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;
import com.mongodb.gridfs.GridFSFile;

import com.unis.common.secure.authc.UserInfo;
import com.unis.common.util.TimeUtil;
import com.unis.common.util.ValidateUtil;
import com.unis.pojo.Attachment;
import com.unis.common.exception.app.UploadFailureException;
import com.unis.pojo.CxFlwsJtl;
import com.unis.pojo.ZfflwsJtl;
import com.unis.service.impl.BaseServiceImpl;
import com.unis.service.system.AttachmentService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.DateUtil;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;

import static java.awt.SystemColor.info;

/**
 * Created by Administrator on 2019/1/30/030.
 */
@Service("attachmentService")
public class AttachmentServiceImpl extends BaseServiceImpl implements AttachmentService {
    private final ExecutorService execService = Executors.newSingleThreadExecutor();

    @Value("${mongo.host}")
    private String mongodbHost;

    @Value("${mongo.port}")
    private String mongodbPort;

    // mongoDB存储名
    private static final String DB_ATTACHMENT = "attachments";
    // 文件存储默认空间名称
    private static final String ATTACHEMENT_DEFAULT_PLACE = "public";

    private MongoClient getMongoClient(MongoClient client) throws UnknownHostException {
        List<ServerAddress> addresses = new ArrayList<ServerAddress>();
        String[] mongodbHosts = mongodbHost.split(",");
        String[] mongodbPorts = mongodbPort.split(",");
        for(int i=0;i<mongodbHosts.length;i++){
            ServerAddress address1 = new ServerAddress(mongodbHosts[i] , Integer.parseInt(mongodbPorts[i]));
            addresses.add(address1);
        }
        client = new MongoClient(addresses);
        return client;
    }
    /**
     * 获取GridFS
     *
     * @param attachment
     * @param client
     * @return
     */
    private GridFS getGridFS(Attachment attachment, MongoClient client) {
        if(attachment!=null){
            String db_attachment=DB_ATTACHMENT;
            if (StringUtils.isNotBlank(attachment.getAttachmentDb())){
                db_attachment = attachment.getAttachmentDb();
            }else{
                attachment.setAttachmentDb(db_attachment);
            }
            DB mongodb = client.getDB(db_attachment);
            UserInfo user = this.getUserInfo();
            /*String place = "";
            String shared = attachment.getShared();
            if (StringUtils.isNotBlank(shared) && !StringUtils.equalsIgnoreCase("true", shared)) {
                // 私有默认采用用户警号作为目录
                if (user != null) {
                    place = user.getJh();
                }
            }
            String default_place = ATTACHEMENT_DEFAULT_PLACE;
            // 如果设置上传目录采用设置参数
            if(StringUtils.isNotBlank(attachment.getCatalog())){
                default_place = attachment.getCatalog();
            }
            place = StringUtils.isBlank(place) ? default_place : place;*/

            String place = ATTACHEMENT_DEFAULT_PLACE;
            if(StringUtils.isNotBlank(attachment.getCatalog())){
                place = attachment.getCatalog();
            }else{
                place = user.getJgdm();
                attachment.setCatalog(place);
            }


            GridFS gridFS = new GridFS(mongodb, place);
            return gridFS;
        }else {
            return null;
        }

    }

    @Override
    public Attachment upload(Attachment attachment) throws UploadFailureException {
        MongoClient client = null;
        try {
            client = getMongoClient(client);
            //client = new MongoClient(mongodbHost, Integer.parseInt(mongodbPort));
            GridFS gridFS = getGridFS(attachment, client);
            GridFSFile fsFile = gridFS.createFile(attachment.getContent());
            ObjectId id = new ObjectId(attachment.getPk());
            fsFile.put("_id", id);
            fsFile.put("filename", attachment.getFilename());
            fsFile.put("contentType", attachment.getContentType());
            fsFile.save();
            assert fsFile.getId().toString().equals(attachment.getPk());
            // attachment.setPk(fsFile.getId().toString());
        } catch (UnknownHostException e) {
            throw new UploadFailureException(e);
        } finally {
            if (client != null) {
                client.close();
            }
        }
        return attachment;
    }

    @Override
    public Attachment download(Attachment attachment) throws UploadFailureException {
        MongoClient client = null;
        try {
            client = getMongoClient(client);
            GridFS gridFS = getGridFS(attachment, client);
            ObjectId id = new ObjectId(attachment.getPk());
            GridFSDBFile fsdbFile = gridFS.find(id);
            if (fsdbFile != null) {
                attachment.setChunkSize(fsdbFile.getChunkSize());
                attachment.setContent(IOUtils.toByteArray(fsdbFile.getInputStream()));
                attachment.setContentType(fsdbFile.getContentType());
                attachment.setFilename(fsdbFile.getFilename());
                attachment.setLength(fsdbFile.getLength());
                attachment.setMd5(fsdbFile.getMD5());
                attachment.setUploadTime(TimeUtil.fmtDate(fsdbFile.getUploadDate(),null));
            }
        } catch (UnknownHostException e) {
            throw new UploadFailureException(e);
        } catch (IOException e) {
            throw new UploadFailureException(e);
        } finally {
            if (client != null) {
                client.close();
            }
        }
        return attachment;
    }

    @Override
    public Image preview(Attachment attachment) throws UploadFailureException {
        attachment = this.download(attachment);
        Image tmpIm = null;
        if (attachment.getContent() != null) {
            File tmp = null;
            try {
                tmp = new File(attachment.getFilename());
                FileUtils.writeByteArrayToFile(tmp, attachment.getContent());
                BufferedImage image = ImageIO.read(tmp);
                if (StringUtils.equals("1", attachment.getRange())) {
                    return image;
                }
                int width = image.getWidth();
                int height = image.getHeight();
                double ratio = 0.;
                int w = 300;
                tmpIm = image.getScaledInstance(w, w, Image.SCALE_SMOOTH);
                if (height > w || width > w) {
                    double wd = 300.;
                    if (height > width) {
                        ratio = wd / height;
                    } else {
                        ratio = wd / width;
                    }
                }
                if (ratio == 0.) {
                    tmpIm = image;
                } else {
                    AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);
                    tmpIm = op.filter(image, null);
                }
            } catch (IOException e) {
                throw new UploadFailureException(e);
            } finally {
                try {
                    FileUtils.deleteDirectory(tmp);
                } catch (IOException e) {
                    throw new UploadFailureException(e);
                }
            }
        }
        return tmpIm;
    }

    @Override
    public void remove(Attachment attachment) throws UploadFailureException {
        MongoClient client = null;
        try {
            client = getMongoClient(client);
            GridFS gridFS = getGridFS(attachment, client);
            ObjectId id = new ObjectId(attachment.getPk());
            gridFS.remove(id);
        } catch (UnknownHostException e) {
            throw new UploadFailureException(e);
        } finally {
            if (client != null) {
                client.close();
            }
        }
    }

    //@Override
    private List<Attachment> queryAttachments(Attachment attachment) throws UploadFailureException {
        MongoClient client = null;
        List<Attachment> attachments = new ArrayList<Attachment>();
        try {
            client = getMongoClient(client);
            GridFS gridFS = getGridFS(attachment, client);
            List<GridFSDBFile> files = gridFS.find(new BasicDBObject("filename", Pattern.compile(attachment
                    .getFilename())));
            for (GridFSDBFile fsdbFile : files) {
                Attachment attach = new Attachment();
                attach.setPk(fsdbFile.getId().toString());
                attach.setChunkSize(fsdbFile.getChunkSize());
                attach.setContent(IOUtils.toByteArray(fsdbFile.getInputStream()));
                attach.setContentType(fsdbFile.getContentType());
                attach.setFilename(fsdbFile.getFilename());
                attach.setLength(fsdbFile.getLength());
                attach.setMd5(fsdbFile.getMD5());
                attach.setUploadTime(TimeUtil.fmtDate(fsdbFile.getUploadDate(), null));
                attachments.add(attach);
            }
        } catch (UnknownHostException e) {
            throw new UploadFailureException(e);
        } catch (IOException e) {
            throw new UploadFailureException(e);
        } finally {
            if (client != null) {
                client.close();
            }
        }
        return attachments;
    }

}
